use hypers::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Extract, Debug, Default)]
#[extract(body)] //这个可以省略不写
pub struct Data<'a> {
    // #[serde(rename = "lastName")]
    #[extract(query, rename = "lastName", alias("lastName", "Last-Name"))]
    pub name: &'a str,

    #[extract(param)]
    pub age: u16,

    #[extract(flatten)]
    pub nested: DataNested<'a>,
}

#[derive(Serialize, Deserialize, Extract, Debug, Default)]
pub struct DataNested<'a> {
    pub email: &'a str,
    pub first_name: &'a str,
    #[extract(param)]
    pub index: u16,
}
struct Api;
#[controller(name = "/")]
impl Api {
    #[post("extract_execute/:age/:index")]
    pub async fn extract_execute<'a>(data: Data<'a>) -> impl Responder {
        let mut res = Response::default();
        res.status(200).json(&data);
        res
    }
}

#[derive(Serialize, Deserialize, Extract, Debug)]
#[extract(body)]
struct GoodMan<'a> {
    #[extract(param)]
    #[serde(default)]
    id: i64,
    #[extract(query)]
    #[serde(default)]
    username: &'a str,
    first_name: String,
    last_name: String,
    lovers: Vec<String>,
    #[extract(flatten)]
    nested: Nested<'a>,
}

#[derive(Serialize, Deserialize, Extract, Debug)]
#[extract(body)]
struct Nested<'a> {
    #[extract(param)]
    #[serde(default)]
    id: i64,
    #[extract(query)]
    #[serde(default)]
    username: &'a str,
    first_name: String,
    last_name: String,
    #[serde(rename = "lovers")]
    #[serde(default)]
    pets: Vec<String>,
}
async fn show(req: Request) -> Response {
    let content = format!(
        r#"<!DOCTYPE html>
    <html>
        <head>
            <title>Parse data</title>
        </head>
        <body>
            <h1>Hello, fill your profile</h1>
            <div id="result"></div>
            <form id="form" method="post">
                <label>First Name:</label><input type="text" name="first_name" />
                <label>Last Name:</label><input type="text" name="last_name" />
                <legend>What is Your Favorite Pet?</legend>
                <input type="checkbox" name="lovers" value="Cats">Cats<br>
                <input type="checkbox" name="lovers" value="Dogs">Dogs<br>
                <input type="checkbox" name="lovers" value="Birds">Birds<br>
                <input type="submit" value="Submit" />
            </form>
            <script>
            let form = document.getElementById("form");
            form.addEventListener("submit", async (e) => {{
                e.preventDefault();
                let response = await fetch('/{}?username=jobs', {{
                    method: 'POST',
                    headers: {{
                        'Content-Type': 'application/json',
                    }},
                    body: JSON.stringify({{
                        first_name: form.querySelector("input[name='first_name']").value,
                        last_name: form.querySelector("input[name='last_name']").value,
                        lovers: Array.from(form.querySelectorAll("input[name='lovers']:checked")).map(el => el.value),
                    }}),
                }});
                let text = await response.text();
                document.getElementById("result").innerHTML = text;
            }});
            </script>
        </body>
    </html>
    "#,
        req.param::<&str>("id").unwrap()
    );
    let res = Response::default();
    res.render(Text::Html(content))
}

async fn edit(mut req: Request) -> Result<Response> {
    let good_man = req.extract::<GoodMan>().await?;
    let mut res = Response::default();
    res.json(&good_man);
    Ok(res)
}

#[tokio::main]
async fn main() -> Result<()> {
    let mut root = Router::default();
    root.get("/:id", show); // http://127.0.0.1:7878/11
    root.post("/:id", edit);
    root.push(Api);
    println!("root = {:#?}", root);
    let listener = hypers::TcpListener::bind("127.0.0.1:7878").await?;
    hypers::listen(root, listener).await
}
